home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Demos / Duel / duel.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  17.8 KB  |  537 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Duel.cpp
  3. //
  4. // Desc: Multi-player game
  5. //
  6. // Copyright (C) 1995-2001 Microsoft Corporation. All Rights Reserved.
  7. //-----------------------------------------------------------------------------
  8. #include "duel.h"
  9. #include "gameproc.h"
  10. #include "gfx.h"
  11. #include "DPUtil.h"
  12. #include "diutil.h"
  13. #include "dsutil.h"
  14. #include "lobby.h"
  15.  
  16.  
  17.  
  18. //-----------------------------------------------------------------------------
  19. // Globals
  20. //-----------------------------------------------------------------------------
  21. // This GUID allows DirectPlay to find other instances of the same game on
  22. // the network.  So it must be unique for every game, and the same for 
  23. // every instance of that game.  // {33925241-05F8-11d0-8063-00A0C90AE891}
  24. GUID g_AppGUID = { 0x33925241, 0x5f8, 0x11d0, { 0x80, 0x63, 0x0, 0xa0, 0xc9, 0xa, 0xe8, 0x91 } };
  25.  
  26. extern DWORD          g_dwFrameCount;
  27. extern DWORD          g_dwFrameTime;
  28. extern int            g_nProgramState;
  29. extern SHIP           g_OurShip;
  30. extern DPID           g_LocalPlayerDPID;
  31.  
  32. static BOOL           g_bReinitialize; // Used for switching display modes
  33.  
  34. TCHAR     g_strAppName[256] = "Duel";               // The name of the sample
  35. HANDLE    g_hDPMessageEvent = NULL;                 // Not used in this sample, needed for DPConnect.cpp
  36. TCHAR     g_strLocalPlayerName[MAX_PLAYER_NAME];    // Local player name
  37. TCHAR     g_strSessionName[MAX_SESSION_NAME];       // Default session name
  38. TCHAR     g_strPreferredProvider[MAX_SESSION_NAME]; // Default preferred provider
  39.  
  40. LPDPLCONNECTION    g_pDPLConnection = NULL;  
  41. LPDIRECTPLAYLOBBY3 g_pDPLobby       = NULL;  
  42.  
  43. HWND      g_hwndMain;             // Main application window handle
  44. HKEY      g_hDuelKey = NULL;      // Duel registry key handle
  45. HINSTANCE g_hInst;                // Application instance handle        
  46. BOOL      g_bShowFrameCount=TRUE; // Show FPS ?
  47. BOOL      g_bIsActive;            // Is the application active ?
  48. BOOL      g_bHostPlayer;          // Are we hosting or joining a game       
  49. DWORD     g_dwKeys;               // User keyboard input
  50. DWORD     g_dwOldKeys;            // Last frame's keyboard input
  51. BOOL      g_bFullscreen=FALSE;    // Window or FullScreen mode ?
  52. RECT      g_rcWindow;             // client rectangle of main window
  53. BOOL      g_bReliable;            // sends are reliable
  54. BOOL      g_bAsync;               // asynchronous sends
  55. BOOL      g_bAsyncSupported;      // asynchronous sends supported
  56. BOOL      g_bUseProtocol;         // DirectPlay Protocol messaging
  57.  
  58.  
  59.  
  60.  
  61. //-----------------------------------------------------------------------------
  62. // Function prototypes
  63. //-----------------------------------------------------------------------------
  64. extern int     DPConnect_StartDirectPlayConnect( HINSTANCE hInst, BOOL bBackTrack = FALSE );
  65. extern HRESULT DPConnect_CheckForLobbyLaunch( BOOL* pbLaunchedByLobby );
  66.  
  67. LRESULT CALLBACK MainWndproc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  68. HRESULT InitApplication( HINSTANCE hInst );
  69. HRESULT ReadRegKey( HKEY hKey, TCHAR* strName, TCHAR* strValue, DWORD dwLength, TCHAR* strDefault );
  70. HRESULT WriteRegKey( HKEY hKey, TCHAR* strName, TCHAR* strValue );
  71. VOID    CleanupApplication();
  72. BOOL    WasLaunchedByLobby();
  73. BOOL    FinishLobbyLaunch();
  74. VOID    DoHelp();
  75.  
  76.  
  77.  
  78.  
  79. //-----------------------------------------------------------------------------
  80. // Name: WinMain()
  81. // Desc:
  82. //-----------------------------------------------------------------------------
  83. int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int )
  84. {
  85.     MSG     msg;
  86.     BOOL    bLaunchedByLobby;
  87.     HRESULT hr;
  88.  
  89.     g_hInst = hInstance;
  90.  
  91.     // Read information from registry
  92.     RegCreateKeyEx( HKEY_CURRENT_USER, DUEL_KEY, 0, NULL,
  93.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  94.                     &g_hDuelKey, NULL );
  95.  
  96.     ReadRegKey( g_hDuelKey, "Player Name", 
  97.                 g_strLocalPlayerName, MAX_PLAYER_NAME, "" );
  98.     ReadRegKey( g_hDuelKey, "Session Name", 
  99.                 g_strSessionName, MAX_SESSION_NAME, "" );
  100.     ReadRegKey( g_hDuelKey, "Preferred Provider", 
  101.                 g_strPreferredProvider, MAX_SESSION_NAME, "" );
  102.  
  103.     CoInitialize( NULL );
  104.  
  105.     if( FAILED( InitApplication( hInstance ) ) )
  106.         return 0;
  107.  
  108.     // See if we were launched from a lobby server
  109.     hr = DPConnect_CheckForLobbyLaunch( &bLaunchedByLobby );
  110.     if( FAILED(hr) )
  111.         return 1;
  112.  
  113.     if( bLaunchedByLobby )
  114.     {
  115.         // Start game
  116.         PostMessage( g_hwndMain, UM_LAUNCH, 0, 0 );
  117.         g_bIsActive = TRUE;
  118.     }
  119.  
  120.     g_dwFrameTime = timeGetTime();
  121.  
  122.     while( TRUE )
  123.     {
  124.         if( g_bIsActive )
  125.         {
  126.             // Any windows messages ? (returns immediately)
  127.             if( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
  128.             {
  129.                 if( !GetMessage( &msg, NULL, 0, 0 ) )
  130.                     break;
  131.  
  132.                 TranslateMessage( &msg );
  133.                 DispatchMessage( &msg );
  134.             }
  135.             else
  136.             {
  137.                 // Poll our receive queue. Polling is used in the sample only for simplicity.
  138.                 // Receiving messages using an event is the recommended way.
  139.                 if( g_nProgramState != PS_SPLASH )
  140.                 {
  141.                     ReceiveMessages();
  142.                     LobbyMessageReceive(LMR_PROPERTIES);
  143.                 }
  144.  
  145.                 // update screen
  146.                 if( !UpdateFrame() )
  147.                     ExitGame();     // posts QUIT msg
  148.             }
  149.         }
  150.         else
  151.         {
  152.             // Any windows messages ? (blocks until a message arrives)
  153.             if( !GetMessage( &msg, NULL, 0, 0 ) )
  154.                 break;
  155.  
  156.             TranslateMessage( &msg );
  157.             DispatchMessage( &msg );
  158.         }
  159.     }
  160.  
  161.     CoUninitialize();
  162.  
  163.     // Write information to the registry
  164.     WriteRegKey( g_hDuelKey, "Player Name", g_strLocalPlayerName );
  165.     WriteRegKey( g_hDuelKey, "Session Name", g_strSessionName );
  166.     WriteRegKey( g_hDuelKey, "Preferred Provider", g_strPreferredProvider );
  167.  
  168.     return (int)msg.wParam;
  169. }
  170.  
  171.  
  172.  
  173.  
  174. //-----------------------------------------------------------------------------
  175. // Name: MainWndproc()
  176. // Desc: Callback for all Windows messages
  177. //-----------------------------------------------------------------------------
  178. LRESULT CALLBACK MainWndproc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  179. {
  180.     PAINTSTRUCT ps;
  181.     HDC         hdc;
  182.  
  183.     switch( msg )
  184.     {
  185.         case WM_SIZE:
  186.         case WM_MOVE:
  187.             // Get the client rectangle
  188.             if( g_bFullscreen )
  189.             {
  190.                 SetRect( &g_rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN),
  191.                          GetSystemMetrics(SM_CYSCREEN) );
  192.             }
  193.             else
  194.             {
  195.                 GetClientRect( hWnd, &g_rcWindow );
  196.                 ClientToScreen( hWnd, (POINT*)&g_rcWindow );
  197.                 ClientToScreen( hWnd, (POINT*)&g_rcWindow+1 );
  198.             }
  199.             break;
  200.  
  201.         case WM_ACTIVATE:
  202.             // Ignore this message during reinitializing graphics
  203.             if( g_bReinitialize )
  204.                 return 0;
  205.  
  206.             // When we are deactivated, although we don't update our screen, we
  207.             // still need to to empty our receive queue periodically as
  208.             // messages will pile up otherwise. Polling the receive queue
  209.             // continuously even when we are deactivated causes our app to
  210.             // consume all the CPU time. To avoid hogging the CPU, we block on
  211.             // GetMessage() WIN API and setup a timer to wake ourselves up at
  212.             // regular intervals to process our messages.
  213.  
  214.             if( LOWORD(wParam) == WA_INACTIVE )
  215.             {
  216.                 // Aeactivated
  217.                 g_bIsActive = FALSE;
  218.                 if( PS_ACTIVE == g_nProgramState )
  219.                     SetTimer( hWnd, RECEIVE_TIMER_ID, RECEIVE_TIMEOUT, NULL );
  220.             }
  221.             else
  222.             {
  223.                 // Activated
  224.                 g_bIsActive = TRUE;
  225.                 if( PS_ACTIVE == g_nProgramState )
  226.                     KillTimer( hWnd, RECEIVE_TIMER_ID );
  227.             }
  228.  
  229.             // set game palette, if activated in game mode
  230.             if( g_bIsActive && (g_nProgramState != PS_SPLASH) )
  231.                 SetGamePalette();
  232.  
  233.             DIUtil_ReacquireInputDevices();
  234.  
  235.             return 0;
  236.  
  237.         case WM_CREATE:
  238.             break;
  239.  
  240.         case WM_SYSKEYUP:
  241.             switch( wParam )
  242.             {
  243.                 // Handle ALT+ENTER (fullscreen/window mode)
  244.                 case VK_RETURN:
  245.                     // Mode switch is allowed only during the game
  246.                     if( g_nProgramState == PS_ACTIVE )
  247.                     {
  248.                         g_bReinitialize = TRUE;
  249.                         ReleaseLocalData();  //only sound buffers have to be rels'd anyway.
  250.                         CleanupGameSounds();
  251.                         DIUtil_CleanupInput();
  252.                         CleanupGraphics();
  253.                         DestroyWindow( g_hwndMain );
  254.                         g_bFullscreen = !g_bFullscreen;
  255.                         InitGraphics();
  256.                         DIUtil_InitInput( g_hwndMain );
  257.                         InitializeGameSounds();
  258.                         InitLocalSoundData();
  259.                         g_bReinitialize = FALSE;
  260.                     }
  261.                     break;
  262.             }
  263.             break;
  264.  
  265.         case WM_KEYDOWN:
  266.             switch( wParam )
  267.             {
  268.                 case 'a':
  269.                 case 'A':
  270.                     // Toggle Async sends on/off
  271.                     if( g_bAsyncSupported )
  272.                     {
  273.                         g_bAsync = !g_bAsync;
  274.                         UpdateTitle();      // caption bar status
  275.                     }
  276.                     break;
  277.  
  278.                 case 'r':
  279.                 case 'R':
  280.                     // Toggle reliable sends
  281.                     g_bReliable = !g_bReliable;
  282.                     UpdateTitle();
  283.                     break;
  284.  
  285.                 case VK_F1:
  286.                     // Display help
  287.                     DoHelp();
  288.                     break;
  289.  
  290.                 case VK_F5:
  291.                     // Toggle frame rate display
  292.                     g_bShowFrameCount = !g_bShowFrameCount;
  293.                     if( g_bShowFrameCount )
  294.                     {
  295.                         g_dwFrameCount = 0;
  296.                         g_dwFrameTime = timeGetTime();
  297.                     }
  298.                     break;
  299.  
  300.                 case VK_RETURN:
  301.                     // Launch game setup wizard
  302.                     if( (g_nProgramState == PS_SPLASH) && !g_bFullscreen )
  303.                     {
  304.                         int nExitCode;
  305.                         nExitCode = DPConnect_StartDirectPlayConnect( g_hInst, FALSE );
  306.  
  307.                         // Figure out what happened, and post a reflecting message
  308.                         if( nExitCode == EXITCODE_FORWARD )
  309.                             PostMessage(g_hwndMain, UM_LAUNCH, 0, 0);
  310.  
  311.                         if( nExitCode == EXITCODE_QUIT )
  312.                             PostMessage(g_hwndMain, UM_ABORT, 0, 0);
  313.  
  314.                         if( nExitCode == EXITCODE_LOBBYCONNECT )
  315.                             PostMessage( g_hwndMain, UM_LAUNCH, 0, 0 );
  316.  
  317.                         if( nExitCode == EXITCODE_ERROR )
  318.                         {
  319.                             MessageBox( g_hwndMain, TEXT("Mutliplayer connect failed. "
  320.                                         "The sample will now quit."),
  321.                                         TEXT("DirectPlay Sample"), MB_OK | MB_ICONERROR );
  322.                             PostMessage(g_hwndMain, UM_ABORT, 0, 0);
  323.                         }
  324.                     }
  325.                     break;
  326.  
  327.                 case VK_ESCAPE:
  328.                 case VK_F12:
  329.                     // Exit the game
  330.                     ExitGame();
  331.                     return 0;
  332.             }
  333.             break;
  334.  
  335.         case WM_ERASEBKGND:
  336.             return 1;
  337.  
  338.         case WM_PAINT:
  339.             hdc = BeginPaint( hWnd, &ps );
  340.             if( g_nProgramState == PS_SPLASH )
  341.             {
  342.                 // Display the splash screen
  343.                 BltSplashScreen( NULL );
  344.             }
  345.  
  346.             EndPaint( hWnd, &ps );
  347.             return 1;
  348.  
  349.         case UM_LAUNCH:
  350.         case UM_ABORT:
  351.             // if we were launched by the lobby and not (failed to finish a lobby launch)
  352.             // where wParam is bLobbyLaunched
  353.             if( msg == UM_LAUNCH )
  354.             {
  355.                 // Init lobby msg support for reporting score
  356.                 // Note that we don't release the lobby object
  357.                 LobbyMessageInit();
  358.  
  359.                 // Start the game in rest mode
  360.                 g_nProgramState = PS_REST;
  361.                 LaunchGame();
  362.                 return 1;
  363.             }
  364.             // Else aborting
  365.             ExitGame();
  366.             return 1;
  367.  
  368.         case WM_TIMER:
  369.             ReceiveMessages();
  370.             LobbyMessageReceive( LMR_PROPERTIES );
  371.             break;
  372.  
  373.         case WM_DESTROY:
  374.             // If g_bReinitialize is TRUE don't quit, we are just switching
  375.             // display modes
  376.             if( !g_bReinitialize )
  377.             {
  378.                 CleanupApplication();
  379.                 PostQuitMessage( 0 );
  380.             }
  381.             return 0;
  382.  
  383.         default:
  384.             break;
  385.     }
  386.  
  387.     return DefWindowProc( hWnd, msg, wParam, lParam );
  388. }
  389.  
  390.  
  391.  
  392. //-----------------------------------------------------------------------------
  393. // Name: InitApplication()
  394. // Desc: Do that initialization stuff...
  395. //-----------------------------------------------------------------------------
  396. HRESULT InitApplication( HINSTANCE hInst )
  397. {
  398.     WNDCLASS wndClass = { CS_DBLCLKS, MainWndproc, 0, 0, hInst,
  399.                           LoadIcon( hInst, MAKEINTRESOURCE(IDI_MAIN)),
  400.                           LoadCursor(NULL, IDC_ARROW), 
  401.                           (HBRUSH)GetStockObject(BLACK_BRUSH),
  402.                           NULL, TEXT("DuelClass") };
  403.     RegisterClass( &wndClass );
  404.  
  405.     // Initialize all components
  406.     if( FAILED( InitGraphics() ) )
  407.         return E_FAIL;
  408.     
  409.     if( FAILED( DIUtil_InitInput( g_hwndMain ) ) )
  410.         return E_FAIL;
  411.  
  412.     if( FAILED( InitializeGameSounds() ) )
  413.     {
  414.         // Can play game without sound. Do not exit
  415.     }
  416.  
  417.     // Start in splash mode
  418.     g_nProgramState = PS_SPLASH;
  419.  
  420.     return S_OK;
  421. }
  422.  
  423.  
  424.  
  425.  
  426. //-----------------------------------------------------------------------------
  427. // Name: CleanupApplication()
  428. // Desc: Calls clean up on all components
  429. //-----------------------------------------------------------------------------
  430. VOID CleanupApplication()
  431. {
  432.     CleanupComm();
  433.     CleanupGameSounds();
  434.     CleanupGraphics();
  435.     DIUtil_CleanupInput();
  436.     DPLobbyRelease();               // in case we were doing lobby messages
  437. }
  438.  
  439.  
  440.  
  441.  
  442. //-----------------------------------------------------------------------------
  443. // Name: ShowError()
  444. // Desc: Displays error to the user
  445. //-----------------------------------------------------------------------------
  446. VOID ShowError( int iStrID )
  447. {
  448.     TCHAR strMsg[MAX_ERRORMSG];
  449.     LoadString( g_hInst, iStrID, strMsg, MAX_ERRORMSG );
  450.     MessageBox( g_hwndMain, strMsg, TEXT("Duel Message"), MB_OK );
  451. }
  452.  
  453.  
  454.  
  455.  
  456. //-----------------------------------------------------------------------------
  457. // Name: UpdateTitle()
  458. // Desc: Updates the window title based on application status
  459. //-----------------------------------------------------------------------------
  460. VOID UpdateTitle()
  461. {
  462.     // Build the window title
  463.     TCHAR strTitle[MAX_WINDOWTITLE] = TEXT("Duel");
  464.  
  465.     // State options in window title
  466.     if( g_bHostPlayer | g_bUseProtocol | g_bReliable | g_bAsync )
  467.     {   
  468.         strcat( strTitle, " - |" );
  469.         if( g_bHostPlayer )
  470.             _tcscat( strTitle, TEXT(" Host |") );
  471.         if( g_bUseProtocol )
  472.             _tcscat( strTitle, TEXT(" Protocol |") );
  473.         if( g_bReliable )
  474.             _tcscat( strTitle, TEXT(" Reliable |") );
  475.         if( g_bAsync )
  476.             _tcscat( strTitle, TEXT(" Async |") );
  477.     }
  478.  
  479.     // Change window title
  480.     SetWindowText( g_hwndMain, strTitle );
  481. }
  482.  
  483.  
  484.  
  485.  
  486. //-----------------------------------------------------------------------------
  487. // Name: DoHelp()
  488. // Desc: Display a Help summary in a message box.
  489. //-----------------------------------------------------------------------------
  490. VOID DoHelp()
  491. {
  492.     TCHAR strHelpMsg[MAX_HELPMSG];
  493.     LoadString( g_hInst, IDS_DUEL_HELP, strHelpMsg, MAX_HELPMSG );
  494.     MessageBox( g_hwndMain, strHelpMsg, TEXT("DUEL"), MB_OK );
  495. }
  496.  
  497.  
  498.  
  499.  
  500. //-----------------------------------------------------------------------------
  501. // Name: ReadRegKey()
  502. // Desc: Read a registry key 
  503. //-----------------------------------------------------------------------------
  504. HRESULT ReadRegKey( HKEY hKey, TCHAR* strName, TCHAR* strValue, 
  505.                     DWORD dwLength, TCHAR* strDefault )
  506. {
  507.     DWORD dwType;
  508.     LONG bResult;
  509.  
  510.     bResult = RegQueryValueEx( hKey, strName, 0, &dwType, 
  511.                              (LPBYTE) strValue, &dwLength );
  512.     if ( bResult != ERROR_SUCCESS )
  513.         strcpy( strValue, strDefault );
  514.  
  515.     return S_OK;
  516. }
  517.  
  518.  
  519.  
  520.  
  521. //-----------------------------------------------------------------------------
  522. // Name: WriteRegKey()
  523. // Desc: Writes a registry key 
  524. //-----------------------------------------------------------------------------
  525. HRESULT WriteRegKey( HKEY hKey, TCHAR* strName, TCHAR* strValue )
  526. {
  527.     LONG bResult;
  528.  
  529.     bResult = RegSetValueEx( hKey, strName, 0, REG_SZ, 
  530.                              (LPBYTE) strValue, strlen(strValue) + 1 );
  531.     if ( bResult != ERROR_SUCCESS )
  532.         return E_FAIL;
  533.  
  534.     return S_OK;
  535. }
  536.  
  537.